package com.qyh.lucas.fsm;

import com.qyh.lucas.TransferEventEnum;
import com.qyh.lucas.model.Definition;
import com.qyh.lucas.model.Fsm;
import lombok.val;

import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.qyh.lucas.utils.ReflectionUtils.getFieldValue;
import static com.qyh.lucas.utils.ReflectionUtils.setFieldValue;
import static org.springframework.util.CollectionUtils.isEmpty;

public class FsmHandler {


    /**
     * 根据指定事件对状态机进行状态转换。
     *
     * @param <T>   状态对象的类型。
     * @param fsm   状态机实例，包含状态字段名称和定义。
     * @param t     当前状态对象，其状态字段的值将被检查和更新。
     * @param event 触发状态转换的事件
     * @return 转换后的状态对象。
     * @throws IllegalArgumentException 如果没有找到匹配的初始状态或事件不存在。
     */
    public static <T> T trans(Fsm fsm, T t, TransferEventEnum event) {

        val allStatusFieldNames = fsm.getStatusFieldNames();
        val allDefinitions = fsm.getDefinitions();
        val allFrom = allDefinitions.stream()
                .map(Definition::getFrom)
                .collect(Collectors.toList());

        // 别名转化为数字
        val handledAllFrom = allFrom.stream()
                .map(from -> from.entrySet()
                        .stream()
                        .collect(Collectors.toMap(Map.Entry::getKey,
                                entry -> dealAlias(fsm, from, entry.getKey())
                        ))).collect(Collectors.toList());

        // 当前状态
        val curStatus = allStatusFieldNames
                .stream()
                .collect(Collectors
                        .toMap(
                                fieldName -> fieldName,
                                fieldName -> getFieldValue(t, fieldName)
                        ));

        // 找到from
        val validFromIndex = IntStream.range(0, handledAllFrom.size())
                .filter(i -> {
                    Map<String, Object> curRealFrom = handledAllFrom.get(i);
                    return allStatusFieldNames
                            .stream()
                            .map(fieldName -> curRealFrom.get(fieldName).equals(curStatus.get(fieldName)))
                            .reduce((a, b) -> a && b)
                            .orElse(false);
                })
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("没有匹配的状态！"));

        val validDefinition = allDefinitions.get(validFromIndex);
        val validTransitions = validDefinition.getTransitions();

        // 切换状态到to
        val validTransition = validTransitions.stream()
                .filter(trans -> event.getDesc().equals(trans.getEvent()))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("该事件不存在！"));

        // 状态改变
        val targetStatus = validTransition.getTo();
        targetStatus
                .keySet()
                .forEach(k -> setFieldValue(t, k, dealAlias(fsm, targetStatus, k)));

        return t;
    }


    public static Object dealAlias(Fsm fsm, Map<String, Object> map, String fieldName) {
        Map<String, Map<String, Object>> allStatusAlias = fsm.getStatusAliasMapping();
        Map<String, Object> aliasForField = allStatusAlias.get(fieldName);
        Object aliasV = map.get(fieldName);
        if (!isEmpty(aliasForField)) {
            Object realV = aliasForField.get(aliasV.toString());
            return realV == null ? aliasV : realV;
        }
        return aliasV;
    }


}
